/*
 * @features: 功能
 * @description: 说明
 * @Date: 2021-10-10 00:14:07
 * @Author: judu233(769471424@qq.com)
 * @LastEditTime: 2022-08-14 13:28:56
 * @LastEditors: judu233
 */

import SqlUtil from "../../Storage/SqlUtil";
import { ExtendsLoad } from "../CCExtends";

/**扩展原型组件 */
@ExtendsLoad(Date)
export class DateConstructorExtends {
    static timeNow() {
        return Math.floor(Date.timeNowMillisecons() / 1000);
    }
    /**返回当前时间的毫秒数 */
    static timeNowMillisecons() {
        let now = new Date();
        return now.getTime();
    }

    /**
     * 补全给定范围的日期
     * https://blog.csdn.net/cjFrontEnd/article/details/103495701
     * @param start 开始日期 
     * @param end  结束日期 '
     * @param type 'date' | "month"
     * @returns str[]
     * @example
     * Date.getDateList('2022-01-01',2022-01-03', 'date' )  => ['2022-01-01','2022-01-02','2022-01-03']
     */
    static getDateList(start: string, end: string, type: 'date' | "month") {
        let getDate = (datestr, type) => {
            const temp = datestr.split("-");
            const date = type === 'date' ? new Date(temp[0], parseInt(temp[1]) - 1, temp[2]) :
                new Date(temp[0], parseInt(temp[1]) - 1);
            return date;
        }
        const startTime = getDate(start, type);
        const endTime = getDate(end, type);
        const arr = [];
        if (!startTime.isVaild() || !endTime.isVaild()) {
            return [];
        }
        do {
            const year = startTime.getFullYear();
            const month = startTime.getMonth() + 1 < 10 ? "0" + (startTime.getMonth() + 1) : startTime.getMonth() + 1;
            const day = startTime.getDate() < 10 ? "0" + startTime.getDate() : startTime.getDate();
            type === 'date' ? startTime.setDate(startTime.getDate() + 1) && arr.push(year + "-" + month + "-" + day) :
                startTime.setMonth(startTime.getMonth() + 1) && arr.push(year + "-" + month);
        }
        while ((endTime.getTime() - startTime.getTime()) >= 0)
        return arr;
    }
}
/**扩展组件实例方法 */
@ExtendsLoad(Date.prototype)
export class DateExtends {
    /**
     * 存储当前日期
     * @param saveStr 要加载存储的key
     */
    static saveDate(saveStr: string) {
        let date = this as any as Date;
        return SqlUtil.setItem(saveStr, date);
    }

    /**
     * 从存储中加载指定字符的数据，并覆盖当前日期
     * @param saveStr 要加载存储的key
     * @param def 默认值    
     */
    static reloadDate(saveStr: string, def = new Date()) {
        try {
            let date = this as any as Date;
            let getDate = SqlUtil.getItem(saveStr, def);
            date.setTime(getDate);
            return true;
        } catch (error) {
            return false;
        }
    }

    /**
     * 根据指定格式输出当前日期
     * @param format 输出格式
     * @returns {str}
     * @example
     * let d = new Date()
     * d.format('yyyy-MM-dd hh:mm:ss')  => '2022-01-31 16:58:22'
     */
    static format(format) {
        let self = this as unknown as Date;
        let date = {
            "M+": self.getMonth() + 1,
            "d+": self.getDate(),
            "h+": self.getHours(),
            "m+": self.getMinutes(),
            "s+": self.getSeconds(),
            "q+": Math.floor((self.getMonth() + 3) / 3),
            "S+": self.getMilliseconds()
        };
        if (/(y+)/i.test(format)) {
            format = format.replace(RegExp.$1, (self.getFullYear() + '').substr(4 - RegExp.$1.length));
        }
        for (let k in date) {
            if (new RegExp("(" + k + ")").test(format)) {
                format = format.replace(RegExp.$1, RegExp.$1.length == 1 ?
                    date[k] : ("00" + date[k]).substr(("" + date[k]).length));
            }
        }
        return format;
    }

    /**
     * 判断当前日期是否为工作日
     * @param workDays  特殊的上班日
     * @param restDays  特殊调休的休假日
     * @returns {boolean}  false 休息   true 工作
     * @example 
     *  let restDaysArr = [['2022-01-31', '2022-02-06'], ['2022-04-03', '2022-04-05'], ['2022-04-30', '2022-05-04'],
     *                   ['2022-06-03', '2022-06-05'],['2022-09-10', '2022-09-12'], ['2022-10-01', '2022-10-07']]; 
     *  let workDayArr = [['2022-01-29', '2022-01-30'], ['2022-04-02', '2022-04-02'], ['2022-04-24', '2022-05-07'],
     *                   ['2022-10-08', '2022-10-09']];
     * new Date().checkIsWorkDay(workDayArr, restDaysArr) => boolean
     */
    static checkIsWorkDay(workDays: [string, string][], restDays: [string, string][]) {
        //上班
        let workDay = workDays.map(day => Date.getDateList(day[0], day[1], 'date')).flat();
        //休假 未成年需要在20-21点能进入游戏
        let tiaoxiu = restDays.map(day => Date.getDateList(day[0], day[1], 'date')).flat();

        let timeStamp = new Date();
        let isWeek = timeStamp.getDay(); //0 周日  6周六
        let y = timeStamp.getFullYear();
        let m = timeStamp.getMonth() + 1;
        let mm = m < 10 ? '0' + m : '' + m;
        let d = timeStamp.getDate() < 10 ? '0' + timeStamp.getDate() : '' + timeStamp.getDate();
        let ymd = `${y}-${mm}-${d}`;
        //判断是否为workDay 必定是工作日
        if (workDay.indexOf(ymd) > -1) {
            return true;
        }
        //判断是否为假期 必定休息
        if (tiaoxiu.indexOf(ymd) > -1) {
            return false;
        }
        //判断是否为周六周天
        if (isWeek == 0 || isWeek == 6) {
            return false
        }
        return true;
    }

    /**
     * 当前date是否为有效日期
     * @returns boole true有效期，false无效日期
     */
    static isVaild() {
        let date = this as any as Date;
        return date instanceof Date && !isNaN(date.getTime());
    }

    /**
     * 判断当前日期与结束日期是否是同一天
     * @param endTime 结束日期
     * @returns 
     */
    static checkIsSameDay(endTime: Date = new Date()) {
        let startTime = this as any as Date;
        let startTimeMs = new Date(startTime.toString()).setHours(0, 0, 0, 0);
        let endTimeMs = new Date(endTime.toString()).setHours(0, 0, 0, 0);
        return startTimeMs === endTimeMs;
    }

    /**
     * 判断old日期是不是同一周，注意周日和周1
     * @param old 
     * @param now 
     * @returns 
     */
    static isSameWeek(old: Date, now = new Date()) {
        let oneDayTime = 1000 * 60 * 60 * 24;
        let old_count = parseInt(String(old.getTime() / oneDayTime));
        let now_other = parseInt(String(now.getTime() / oneDayTime));
        return parseInt(String((old_count + 4) / 7)) == parseInt(String((now_other + 4) / 7));
    }
    /**
     * @description 判断两个时间是否是同一周
     * 所有时间都是从 1970年1月1日(周4) 开始，(天数 + 4)/7 就是周数，如果相同则是同一周
     * 特殊情况：周日会是整数，如果直接取整，周日会和下周一是同一天
     * (+new Date('1970-01-01') / oneDay) + 4 / 7  // 周四 = 0.57
     * (+new Date('1970-01-04') / oneDay) + 4 / 7  // 周日 = 1
     * (+new Date('1970-01-05') / oneDay) + 4 / 7  // 周一 = 1.14
     * @params { Stirng } timeA '1970-01-03'
     * @params { Stirng } timeB '1970-01-22'
     */
    static isSameWeek2(timeA: Date, timeB: Date = new Date()) {
        // 获取周数
        let getWeekIndex = (time: Date) => {
            let oneDayTime = 24 * 3600 * 1000;
            let dayCount = time.getTime() / oneDayTime;
            let weekCount = (dayCount + 4) / 7;
            return weekCount;
        };
        let weekIndexA = getWeekIndex(timeA);
        let weekIndexB = getWeekIndex(timeB);
        let tempArr = [weekIndexA, weekIndexB].sort((a, b) => a - b);
        // 如果有周日，间隔 < 1，则是 [1.9, 2] 或 [1, 1.14]，
        // 较大的数为整数则是同一周。间隔 >=1 则不是同一周
        if (tempArr.some(item => Number.isInteger(item))) {
            return tempArr[1] - tempArr[0] < 1 ? Number.isInteger(tempArr[1]) : false;
        } else {
            return parseInt(String(weekIndexA)) === parseInt(String(weekIndexB));
        }
    }

    /**
     * 完美判断版本
     * @param d1 
     * @param d2 
     * @returns 
     */
    static isSameWeek3(d1: Date, d2 = new Date()) {
        const ONE_DAY = 1000 * 60 * 60 * 24;
        const difftime = Math.abs(d2.getTime() - d1.getTime());
        let bigDay = (d1 > d2 ? d1.getDay() : d2.getDay()) || 7;
        let smallDay = (d1 < d2 ? d1.getDay() : d2.getDay()) || 7;
        return !(difftime >= ONE_DAY * 7 || bigDay < smallDay || (bigDay === smallDay && difftime > ONE_DAY));
    }

    /**
      * 获取距离n天的时间(按凌晨计时)
      * @param day 距离天数，默认1天
      * @param curDayTime 当前时间
      * @returns Time
      */
    static getNextDayDate(day = 1, curDayTime = new Date()) {
        let nextDayTime = new Date(curDayTime);
        nextDayTime.setHours(24 * day, 0, 0);
        return nextDayTime;
    }

    /**
    * 根据指定时间，获取距离指定时间n天的剩余时间的倒计时（按凌晨计时)
    * @param day 距离天数，默认1天
    * @param curDayTime 当前时间
    * @returns Time
    */
    static getNextDayRemaining(day = 1, curDayTime = new Date()) {
        let nextDate = this.getNextDayDate(day, curDayTime);
        let sub = nextDate.getTime() - curDayTime.getTime();
        return new Date(sub);
    }
}
